home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #3 & #4 / Amiga Plus CD - 1995 - No. 3 and 4.iso / pd / sound / cybersound / 14bit.driver / source / driver.c < prev    next >
C/C++ Source or Header  |  1995-07-20  |  17KB  |  741 lines

  1.  
  2. /*****************************************************************************
  3.  *
  4.  * CyberSound: 14 Bit sound driver
  5.  *
  6.  * (c) 1995 by Christian Buchner
  7.  *
  8.  *****************************************************************************
  9.  *
  10.  * Driver.c
  11.  */
  12.  
  13. #include <exec/interrupts.h>
  14. #include <exec/memory.h>
  15. #include <exec/execbase.h>
  16. #include <graphics/displayinfo.h>
  17. #include <intuition/intuitionbase.h>
  18. #include <devices/audio.h>
  19. #include <hardware/custom.h>
  20. #include <hardware/intbits.h>
  21. #include <hardware/dmabits.h>
  22. #include <hardware/adkbits.h>
  23. #include <hardware/cia.h>
  24. #include <clib/alib_protos.h>
  25. #include <proto/graphics.h>
  26. #include <proto/dos.h>
  27. #include <stdarg.h>
  28.  
  29. #include "Driver.h"
  30. #include "DriverBase.h"
  31.  
  32. void KPrintF(UBYTE *fmt,...);
  33.  
  34. #define DB(x) 
  35.  
  36.  
  37. /*****************************************************************************/
  38.  
  39. #define TABLE_SIZE (65536*sizeof(UWORD))  /* 2^16 UWORDS */
  40.  
  41.  
  42. /*****************************************************************************/
  43.  
  44. #define DMABUF_SIZE (4*BUFFER_SIZE)    /* The byte size of one audio buffer */
  45.  
  46. #define LEFT_MSB        (0*BUFFER_SIZE)
  47. #define RIGHT_MSB        (1*BUFFER_SIZE)
  48. #define RIGHT_LSB        (2*BUFFER_SIZE)
  49. #define LEFT_LSB        (3*BUFFER_SIZE)
  50.  
  51. /* Buffer layout:
  52.  
  53.    1) Left  channel MSB Bytes  -> Audio Channel 1
  54.    2) Right channel MSB Bytes  -> Audio Channel 2
  55.    3) Right channel LSB Bytes  -> Audio Channel 3
  56.    4) Left  channel LSB Bytes  -> Audio Channel 4
  57.  
  58. */
  59.  
  60.  
  61. /*****************************************************************************/
  62.  
  63. #define AUDIO_INTERRUPTS    (INTF_AUD0|INTF_AUD1|INTF_AUD2|INTF_AUD3)
  64. #define INTERRUPT_USED        (INTF_AUD3)
  65. #define INTERRUPTS_NOT_USED    (INTF_AUD0|INTF_AUD1|INTF_AUD2)
  66.  
  67.  
  68. /*****************************************************************************/
  69.  
  70. BOOL InitDriver( struct DriverBase *db )
  71. {
  72.     struct Custom *custom = (struct Custom*)0xdff000;
  73.     UBYTE ChannelMap[]={0xf};
  74.     BOOL LoadSuccess=FALSE;
  75.     BPTR FH;
  76.     UWORD i;
  77.     
  78.     DB(KPrintF("\n>>> INITIALIZATION <<<\n"));
  79.     
  80.     if (AudioReply=CreateMsgPort())
  81.     {
  82.         if (AudioRequest=CreateIORequest(AudioReply,sizeof(struct IOAudio)))
  83.         {
  84.             AudioRequest->ioa_Request.io_Message.mn_Node.ln_Pri=127;
  85.             AudioRequest->ioa_Data=ChannelMap;
  86.             AudioRequest->ioa_Length=sizeof(ChannelMap);
  87.             AudioRequest->ioa_Request.io_Flags=ADIOF_NOWAIT;
  88.             
  89.             if (!OpenDevice("audio.device",0,(struct IORequest*)AudioRequest,0))
  90.             {
  91.                 if (ConversionTable=AllocVec(TABLE_SIZE,MEMF_ANY))
  92.                 {
  93.                     if (AdditiveArray=AllocVec(256,MEMF_ANY))
  94.                     {
  95.                         if (FH=Open("ENV:CyberSound/SoundDrivers/14Bit_Calibration",MODE_OLDFILE))
  96.                         {
  97.                             if (Read(FH,AdditiveArray,256)==256)
  98.                             {
  99.                                 LoadSuccess=TRUE;
  100.                             }
  101.                             Close(FH);
  102.                         }
  103.                         if (!LoadSuccess)
  104.                         {
  105.                             for (i=0;i<255;i++) AdditiveArray[i]=0x55;
  106.                             AdditiveArray[255]=0x7f;
  107.                         }
  108.                         CreateTable(ConversionTable,AdditiveArray);
  109.                         CurrentFormat=STREAM_16BIT_MOTOROLA;
  110.                         
  111.                         AudioVector.is_Node.ln_Type=
  112.                           NOPVector.is_Node.ln_Type=NT_INTERRUPT;
  113.                         AudioVector.is_Node.ln_Name=
  114.                           NOPVector.is_Node.ln_Name="14 bit driver";
  115.                         AudioVector.is_Data=
  116.                           NOPVector.is_Data=db;
  117.                         AudioVector.is_Code=(void*)(&AudioInterrupt);
  118.                           NOPVector.is_Code=(void*)(&NOPInterrupt);
  119.                         
  120.                         custom->dmacon=    DMAF_AUDIO;
  121.                         custom->adkcon=    ADKF_USE3PN|ADKF_USE2P3|
  122.                                         ADKF_USE1P2|ADKF_USE0P1|
  123.                                         ADKF_USE3VN|ADKF_USE2V3|
  124.                                         ADKF_USE1V2|ADKF_USE0V1;
  125.                         
  126.                         OldAudVector0=SetIntVector(INTB_AUD0,&NOPVector);
  127.                         OldAudVector1=SetIntVector(INTB_AUD1,&NOPVector);
  128.                         OldAudVector2=SetIntVector(INTB_AUD2,&NOPVector);
  129.                         OldAudVector3=SetIntVector(INTB_AUD3,&AudioVector);
  130.                         
  131.                         custom->intena=custom->intreq=AUDIO_INTERRUPTS;
  132.                         custom->intena=INTF_SETCLR|INTERRUPT_USED;
  133.                         
  134.                         NestLevel=0;
  135.                         DriverFlags = FLGF_NEEDIRQ;
  136.                         
  137.                         if (SetBuffers(1024,16,db))
  138.                         {
  139.                             return(TRUE);
  140.                         }
  141.                     }
  142.                 }
  143.             }
  144.         }
  145.     }
  146.     DeInitDriver(db);
  147.     return(FALSE);
  148. }
  149.  
  150.  
  151. /*****************************************************************************/
  152.  
  153. void DeInitDriver( struct DriverBase *db )
  154. {
  155.     struct Custom *custom = (struct Custom*)0xdff000;
  156.     
  157.     DB(KPrintF("\n>>> DE-INITIALIZATION <<<\n"));
  158.     
  159.     if (AudioRequest)
  160.     {
  161.         if (AudioRequest->ioa_Request.io_Device)
  162.         {
  163.             FreeBuffers(db);
  164.             
  165.             custom->intena=custom->intreq=AUDIO_INTERRUPTS;
  166.             
  167.             if (OldAudVector0) SetIntVector(INTB_AUD0,OldAudVector0);
  168.             if (OldAudVector1) SetIntVector(INTB_AUD1,OldAudVector1);
  169.             if (OldAudVector2) SetIntVector(INTB_AUD2,OldAudVector2);
  170.             if (OldAudVector3) SetIntVector(INTB_AUD3,OldAudVector3);
  171.             
  172.             if (AdditiveArray)
  173.             {
  174.                 FreeVec(AdditiveArray);
  175.                 AdditiveArray=NULL;
  176.             }
  177.             
  178.             if (ConversionTable)
  179.             {
  180.                 FreeVec(ConversionTable);
  181.                 ConversionTable=NULL;
  182.             }
  183.             
  184.             CloseDevice((struct IORequest*)AudioRequest);
  185.             AudioRequest->ioa_Request.io_Device=NULL;
  186.         }
  187.         DeleteIORequest(AudioRequest);
  188.         AudioRequest=NULL;
  189.     }
  190.     if (AudioReply)
  191.     {
  192.         DeleteMsgPort(AudioReply);
  193.         AudioReply=NULL;
  194.     }
  195. }
  196.  
  197.  
  198. /*****************************************************************************/
  199.  
  200. BOOL __asm SetBuffers( register __d0 ULONG audiosize, register __d1 ULONG queuesize, register __a6 struct DriverBase *db)
  201. {
  202.     BOOL Success=FALSE;
  203.     
  204.     FreeBuffers(db);
  205.     
  206.     BUFFER_SIZE=audiosize;
  207.     QUEUE_SIZE=queuesize;
  208.     
  209.     if (DMABuffer1=AllocVec(DMABUF_SIZE,MEMF_CHIP))
  210.     {
  211.         if (DMABuffer2=AllocVec(DMABUF_SIZE,MEMF_CHIP))
  212.         {
  213.             if (QueueBuffer=AllocVec(QUEUE_SIZE*sizeof(struct StreamInfo),MEMF_CLEAR))
  214.             {
  215.                 /* Flush (Initialize!) stream */
  216.                 FlushStream(db);
  217.                 
  218.                 Success=TRUE;
  219.             }
  220.         }
  221.     }
  222.     if (!Success) FreeBuffers(db);
  223.     
  224.     return(Success);
  225. }
  226.  
  227.  
  228. /*****************************************************************************/
  229.  
  230. void __asm FreeBuffers( register __a6 struct DriverBase *db )
  231. {
  232.     FlushStream(db);
  233.     
  234.     if (DMABuffer1)
  235.     {
  236.         FreeVec(DMABuffer1);
  237.         DMABuffer1=NULL;
  238.     }
  239.     if (DMABuffer2)
  240.     {
  241.         FreeVec(DMABuffer2);
  242.         DMABuffer2=NULL;
  243.     }
  244.     if (QueueBuffer)
  245.     {
  246.         FreeVec(QueueBuffer);
  247.         QueueBuffer=NULL;
  248.     }
  249.     
  250.     BUFFER_SIZE=0;
  251.     QUEUE_SIZE=0;
  252. }
  253.  
  254.  
  255. /*****************************************************************************/
  256.  
  257. BOOL __asm StreamFormat( register __d0 ULONG format, register __a6 struct DriverBase *db )
  258. {
  259.     BOOL Success=FALSE;
  260.     
  261.     FlushStream(db);
  262.     
  263.     if ( (format==STREAM_16BIT_INTEL    && CurrentFormat==STREAM_16BIT_MOTOROLA) || 
  264.          (format==STREAM_16BIT_MOTOROLA && CurrentFormat==STREAM_16BIT_INTEL   ) )
  265.     {
  266.         SwapEndian(ConversionTable);
  267.         CurrentFormat=format;
  268.         Success=TRUE;
  269.     }
  270.     
  271.     return(Success);
  272. }
  273.  
  274.  
  275. /*****************************************************************************/
  276.  
  277. ULONG __asm AskFrequency( register __d0 ULONG frequency, register __a6 struct DriverBase *db )
  278. {
  279.     UWORD period;
  280.     ULONG result;
  281.     
  282.     period=AskPeriod(frequency,db);
  283.     
  284.     result=(*(struct ExecBase**)(4))->ex_EClockFrequency*5/period;
  285.     
  286.     return(result);
  287. }
  288.  
  289.  
  290. /*****************************************************************************/
  291.  
  292. ULONG __asm AskPeriod( register __d0 ULONG frequency, register __a6 struct DriverBase *db )
  293. {
  294.     UWORD period;
  295.     ULONG ModeID;
  296.     struct MonitorInfo mon;
  297.     
  298.     /* See if front screen has changed */
  299.     if (IntuitionBase->FirstScreen != CurrentScreen)
  300.     {
  301.         /* Store as new current screen and check for NULL ptr */
  302.         if (CurrentScreen=IntuitionBase->FirstScreen)
  303.         {
  304.             /* Get mode ID */
  305.             ModeID=GetVPModeID(&CurrentScreen->ViewPort);
  306.             
  307.             /* See if current mode ID has changed */
  308.             if (ModeID != CurrentModeID)
  309.             {
  310.                 /* Store as new current Mode ID */
  311.                 CurrentModeID=ModeID;
  312.                 
  313.                 /* Get information on current Mode ID */
  314.                 GetDisplayInfoData(NULL,(UBYTE*)&mon,sizeof(mon),DTAG_MNTR,ModeID);
  315.                 
  316.                 /* Calculate minimal period value for current ModeID */
  317.                 CurrentMinPer=mon.TotalColorClocks*mon.TotalRows/(2*(mon.TotalRows-mon.MinRow+1));
  318.             }
  319.         }
  320.     }
  321.     
  322.     period=((*(struct ExecBase**)(4))->ex_EClockFrequency*5+(frequency/2))/frequency;
  323.     
  324.     if (period<CurrentMinPer) period=CurrentMinPer;
  325.     
  326.     return(period);
  327. }
  328.  
  329.  
  330. /*****************************************************************************/
  331.  
  332. BOOL __asm ProvideStream(    register __a0 UWORD *left,
  333.                             register __a1 UWORD *right,
  334.                             register __d0 ULONG samples, 
  335.                             register __d1 UWORD interleave,
  336.                             register __d2 ULONG frequency,
  337.                             register __a2 void (*callback)(void),
  338.                             register __a6 struct DriverBase *db)
  339. {
  340.     struct Custom *custom = (struct Custom*)0xdff000;
  341.     struct StreamInfo *SI;
  342.     BOOL Success=FALSE;
  343.     
  344.     DB(KPrintF("***SUPPLY(%ld) ",samples));
  345.     
  346.     /* Only supply if there are buffers to store it */
  347.     if (QueueBuffer && DMABuffer1 && DMABuffer2)
  348.     {
  349.         /* check if there is enough room in the queue */
  350.         if (((ProvidePos+1)%QUEUE_SIZE)!=PlayPos)
  351.         {
  352.             /* Arbitrate list by disabling the Audio Interrupt */
  353.             SD_Lock(db);
  354.             
  355.             SI= &QueueBuffer[ProvidePos];
  356.             
  357.             SI->si_left=left;
  358.             SI->si_right=right;
  359.             SI->si_samples=samples;
  360.             SI->si_interleave=interleave;
  361.             SI->si_period=AskPeriod(frequency,db);
  362.             SI->si_callback=callback;
  363.             SI->si_offset=0;
  364.             
  365.             ProvidePos=(ProvidePos+1)%QUEUE_SIZE;
  366.             
  367.             /* Cause an audio interrupt if needed */
  368.             if (DriverFlags & FLGF_NEEDIRQ)
  369.             {
  370.                 DB(KPrintF("CAUSE "));
  371.                 
  372.                 DriverFlags &= (~FLGF_NEEDIRQ);
  373.                 custom->intreq = INTF_SETCLR|INTERRUPT_USED;
  374.             }
  375.             
  376.             /* Re-enable Audio Interrupt */
  377.             SD_Unlock(db);
  378.             
  379.             Success=TRUE;
  380.         }
  381.         else
  382.         {
  383.             DB(KPrintF("QUEUE FULL! "));
  384.         }
  385.     }
  386.     else
  387.     {
  388.         DB(KPrintF("NO QUEUE! "));
  389.     }
  390.     DB(KPrintF("\n"));
  391.     return(Success);
  392. }
  393.  
  394.  
  395. /*****************************************************************************/
  396.  
  397. void __asm FlushStream( register __a6 struct DriverBase *db )
  398. {
  399.     struct Custom *custom = (struct Custom*)0xdff000;
  400.     
  401.     DB(KPrintF("***FLUSH "));
  402.     
  403.     /* Only flush if there is a queue to flush */
  404.     if (QueueBuffer)
  405.     {
  406.         DB(KPrintF("CAUSE "));
  407.         
  408.         /* Set FLUSH flag and cause an audio interrupt */
  409.         DriverFlags |= FLGF_FLUSH;
  410.         custom->intreq=INTF_SETCLR|INTERRUPT_USED;
  411.         
  412.         /* Problem: Interrupt may occur somewhat delayed ;-( */
  413.         /* This might speed it up a bit ;-) */
  414.         
  415.         custom->aud[0].ac_per=
  416.         custom->aud[1].ac_per=
  417.         custom->aud[2].ac_per=
  418.         custom->aud[3].ac_per=1;
  419.     }
  420.     DB(KPrintF("\n"));
  421. }
  422.  
  423.  
  424. /*****************************************************************************/
  425.  
  426. void __asm PauseStream( register __a6 struct DriverBase *db )
  427. {
  428.     DB(KPrintF("***PAUSE "));
  429.     
  430.     /* set pause flag */
  431.     DriverFlags |= FLGF_PAUSE;
  432.     
  433.     DB(KPrintF("\n"));
  434. }
  435.  
  436.  
  437. /*****************************************************************************/
  438.  
  439. void __asm ResumeStream( register __a6 struct DriverBase *db )
  440. {
  441.     struct Custom *custom = (struct Custom*)0xdff000;
  442.     
  443.     DB(KPrintF("***RESUME "));
  444.     
  445.     /* clear pause flag */
  446.     DriverFlags &= ~(FLGF_PAUSE);
  447.     
  448.     /* cause an audio interrupt if needed */
  449.     if (DriverFlags & FLGF_NEEDIRQ)
  450.     {
  451.         DB(KPrintF("CAUSE "));
  452.         
  453.         DriverFlags &= (~FLGF_NEEDIRQ);
  454.         custom->intreq = INTF_SETCLR|INTERRUPT_USED;
  455.     }
  456.     
  457.     DB(KPrintF("\n"));
  458. }
  459.  
  460.  
  461. /*****************************************************************************/
  462.  
  463. void __asm AudioInterrupt( register __d1 UWORD ActiveInt, register __a0 struct Custom * custom, register __a1 struct DriverBase *db, register __a6 SysBase )
  464. {
  465.     struct StreamInfo *SI;
  466.     UBYTE *Bufferptr;
  467.     ULONG Chunklen,Playlen;
  468.     UWORD Period=0;
  469.     ULONG Pos;
  470.     struct CIA *ciaa=(struct CIA*)0xbfe001;
  471.     
  472.     /* clear interrupt request bits */
  473.     custom->intreq=(ActiveInt & INTERRUPT_USED);
  474.     
  475.     /* switch off audio filter */
  476.     ciaa->ciapra |= CIAF_LED;
  477.     
  478.     DB(KPrintF("***IRQ "));
  479.     
  480.     /* Set period of the current DMA cycle */
  481.     if (DriverFlags & FLGF_PLAYING)
  482.     {
  483.         custom->aud[0].ac_per=
  484.         custom->aud[1].ac_per=
  485.         custom->aud[2].ac_per=
  486.         custom->aud[3].ac_per=LastPeriod;
  487.     }
  488.     else
  489.     {
  490.         /* Not playing? We we need an IRQ to restart */
  491.         DriverFlags |= FLGF_NEEDIRQ;
  492.     }
  493.     
  494.     /* Delete blocks that have been played completely */
  495.     /* and delete ALL blocks if the FLUSH bit is set */
  496.     for(PlayPos;PlayPos!=ProvidePos;PlayPos=(PlayPos+1)%QUEUE_SIZE)
  497.     {
  498.         SI= &QueueBuffer[PlayPos];
  499.         
  500.         if ((SI->si_offset == 0xffffffff) || (DriverFlags&FLGF_FLUSH))
  501.         {
  502.             DB(KPrintF("DELBLK "));
  503.             
  504.             /* See if this was the last block or if the FLUSH bit is set */
  505.             if ((((PlayPos+1)%QUEUE_SIZE)==ProvidePos) || (DriverFlags&FLGF_FLUSH))
  506.             {
  507.                 /* Stop DMA, nothing more to play */
  508.                 StopDMA(db);
  509.             }
  510.             
  511.             /* Call callback hook */
  512.             if (SI->si_callback) (SI->si_callback)();
  513.         }
  514.         else break;
  515.     }
  516.     
  517.     /* Some more actions to take on FLUSH request */
  518.     if (DriverFlags & FLGF_FLUSH)
  519.     {
  520.         DB(KPrintF("FLUSHED "));
  521.         
  522.         /* Reset pointers */
  523.         CurrentBuffer=1;
  524.         ProvidePos=0;
  525.         PlayPos=0;
  526.         
  527.         /* Reset the flags bits */
  528.         DriverFlags &= ~(FLGF_FLUSH|FLGF_PLAYING);
  529.         DriverFlags |= FLGF_NEEDIRQ;
  530.     }
  531.     else
  532.     {
  533.         /* Mark blocks for deletion that are almost played */
  534.         for (Pos=PlayPos;Pos!=ProvidePos;Pos=(Pos+1)%QUEUE_SIZE)
  535.         {
  536.             SI= &QueueBuffer[Pos];
  537.             
  538.             /* Block finished but still playing? */
  539.             if (SI->si_offset==SI->si_samples)
  540.             {
  541.                 DB(KPrintF("MARKDEL "));
  542.                 
  543.                 /* Mark block as deletable for next interrupt */
  544.                 SI->si_offset= 0xffffffff;
  545.                 
  546.                 /* See if we have a successor block */
  547.                 if (((Pos+1)%QUEUE_SIZE)==ProvidePos)
  548.                 {
  549.                     DB(KPrintF("NEEDIRQ "));
  550.                     
  551.                     /* No successor! We need an IRQ when one is provided */
  552.                     DriverFlags |= FLGF_NEEDIRQ;
  553.                 }
  554.             }
  555.             else break;
  556.         }
  557.         
  558.         /* Actions to take on PAUSE request */
  559.         if (DriverFlags & FLGF_PAUSE)
  560.         {
  561.             /* And stop the DMA right now */
  562.             StopDMA(db);
  563.         }
  564.         else
  565.         {
  566.             /* Get current buffer pointer */
  567.             if (CurrentBuffer == 1)
  568.             {
  569.                 DB(KPrintF("BUF1 "));
  570.                 Bufferptr=DMABuffer1;
  571.             }
  572.             else
  573.             {
  574.                 DB(KPrintF("BUF2 "));
  575.                 Bufferptr=DMABuffer2;
  576.             }
  577.             
  578.             /* Fill buffer until filled */
  579.             for (Playlen=0;(Playlen<BUFFER_SIZE) && (Pos!=ProvidePos);Pos=(Pos+1)%QUEUE_SIZE)
  580.             {
  581.                 SI= &QueueBuffer[Pos];
  582.                 
  583.                 /* get length of current block */
  584.                 Chunklen = SI->si_samples-SI->si_offset;
  585.                 if (Chunklen>0)
  586.                 {
  587.                     /* maximize chunklen to buffer size */
  588.                     if (Chunklen > BUFFER_SIZE-Playlen)
  589.                     {
  590.                         Chunklen = BUFFER_SIZE-Playlen;
  591.                     }
  592.                     
  593.                     /* Make sure that period remains constant in one DMA cycle */
  594.                     if (Period)
  595.                     {
  596.                         if (Period != SI->si_period) break;
  597.                     }
  598.                     else
  599.                     {
  600.                         Period=SI->si_period;
  601.                     }
  602.                     
  603.                     DB(KPrintF("CONVERT(%ld,%ld) ",Chunklen,(ULONG)Period));
  604.                     
  605.                     /* Convert left channel */
  606.                     ConvertStream(    SI->si_left+SI->si_offset*(SI->si_interleave+1),
  607.                                     Bufferptr+LEFT_MSB+Playlen,
  608.                                     Bufferptr+LEFT_LSB+Playlen,
  609.                                     ConversionTable,
  610.                                     Chunklen,
  611.                                     SI->si_interleave);
  612.                     
  613.                     /* Convert right channel */
  614.                     ConvertStream(    SI->si_right+SI->si_offset*(SI->si_interleave+1),
  615.                                     Bufferptr+RIGHT_MSB+Playlen,
  616.                                     Bufferptr+RIGHT_LSB+Playlen,
  617.                                     ConversionTable,
  618.                                     Chunklen,
  619.                                     SI->si_interleave);
  620.                     
  621.                     /* Increment offset */
  622.                     SI->si_offset+=Chunklen;
  623.                     
  624.                     Playlen+=Chunklen;
  625.                 }
  626.             }
  627.             
  628.             if (Playlen)
  629.             {
  630.                 DB(KPrintF("PLAY(%ld,%ld) ",Playlen,(ULONG)Period));
  631.                 
  632.                 LastPeriod=Period;
  633.                 
  634.                 custom->aud[0].ac_ptr=(UWORD*)(Bufferptr+LEFT_MSB);
  635.                 custom->aud[1].ac_ptr=(UWORD*)(Bufferptr+RIGHT_MSB);
  636.                 custom->aud[2].ac_ptr=(UWORD*)(Bufferptr+RIGHT_LSB);
  637.                 custom->aud[3].ac_ptr=(UWORD*)(Bufferptr+LEFT_LSB);
  638.                 
  639.                 custom->aud[0].ac_vol=
  640.                 custom->aud[1].ac_vol=64;
  641.                 custom->aud[2].ac_vol=
  642.                 custom->aud[3].ac_vol=1;
  643.                 
  644.                 custom->aud[0].ac_len=
  645.                 custom->aud[1].ac_len=
  646.                 custom->aud[2].ac_len=
  647.                 custom->aud[3].ac_len=Playlen/2;
  648.                 
  649.                 /* If not already playing, start to do so */
  650.                 
  651.                 if (!(DriverFlags & FLGF_PLAYING))
  652.                 {
  653.                     DB(KPrintF("STARTDMA "));
  654.                     
  655.                     DriverFlags |= FLGF_PLAYING;
  656.                     custom->aud[0].ac_per=
  657.                     custom->aud[1].ac_per=
  658.                     custom->aud[2].ac_per=
  659.                     custom->aud[3].ac_per=Period;
  660.                     custom->dmacon = DMAF_SETCLR|DMAF_AUDIO;
  661.                 }
  662.                 
  663.                 /* Swap current buffer */
  664.                 if (CurrentBuffer == 1)
  665.                 {
  666.                     CurrentBuffer=2;
  667.                 }
  668.                 else
  669.                 {
  670.                     CurrentBuffer=1;
  671.                 }
  672.             }
  673.         }
  674.     }
  675.     DB(KPrintF("\n"));
  676. }
  677.  
  678.  
  679. /*****************************************************************************/
  680.  
  681. void __asm StopDMA( register __a6 struct DriverBase *db )
  682. {
  683.     struct Custom *custom = (struct Custom*)0xdff000;
  684.     
  685.     /* If DMA active, stop it right now */
  686.     if (DriverFlags&FLGF_PLAYING)
  687.     {
  688.         DB(KPrintF("STOPDMA "));
  689.         
  690.         /* Reset driver flags */
  691.         DriverFlags &= (~FLGF_PLAYING);
  692.         DriverFlags |= FLGF_NEEDIRQ;
  693.         
  694.         /* Stop the audio DMA */
  695.         custom->dmacon = DMAF_AUDIO;
  696.         custom->aud[0].ac_vol=
  697.         custom->aud[1].ac_vol=
  698.         custom->aud[2].ac_vol=
  699.         custom->aud[3].ac_vol=0;
  700.     }
  701. }
  702.  
  703.  
  704. /*****************************************************************************/
  705.  
  706. void __asm NOPInterrupt(register __d1 UWORD ActiveInt, register __a0 struct Custom * custom, register __a1 struct DriverBase *db, register __a6 SysBase)
  707. {
  708.     custom->intreq=(ActiveInt & INTERRUPTS_NOT_USED);
  709. }
  710.  
  711.  
  712. /*****************************************************************************/
  713.  
  714. void __asm SD_Lock( register __a6 struct DriverBase *db )
  715. {
  716.     struct Custom *custom = (struct Custom*)0xdff000;
  717.     
  718.     if (NestLevel==0)
  719.     {
  720.         custom->intena=INTERRUPT_USED;
  721.     }
  722.     NestLevel++;
  723. }
  724.  
  725.  
  726. /*****************************************************************************/
  727.  
  728. void __asm SD_Unlock( register __a6 struct DriverBase *db )
  729. {
  730.     struct Custom *custom = (struct Custom*)0xdff000;
  731.     
  732.     if (NestLevel!=0)
  733.     {
  734.         NestLevel--;
  735.         if (NestLevel==0)
  736.         {
  737.             custom->intena=INTF_SETCLR|INTERRUPT_USED;
  738.         }
  739.     }
  740. }
  741.